import config from '@/config'

export function debounce(fn, delay) {

    // 定时器，用来 setTimeout
    var timer

    // 返回一个函数，这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
    return function () {
        // 保存函数调用时的上下文和参数，传递给 fn
        var context = this
        var args = arguments

        // 每次这个返回的函数被调用，就清除定时器，以保证不执行 fn
        clearTimeout(timer)

        // 当返回的函数被最后一次调用后（也就是用户停止了某个连续的操作），
        // 再过 delay 毫秒就执行 fn
        timer = setTimeout(function () {
            fn.apply(context, args)
        }, delay)
    }
}

export function throttle (func, wait, options) {
    /* options的默认值
     *  表示首次调用返回值方法时，会马上调用func；否则仅会记录当前时刻，当第二次调用的时间间隔超过wait时，才调用func。
     *  options.leading = true;
     * 表示当调用方法时，未到达wait指定的时间间隔，则启动计时器延迟调用func函数，若后续在既未达到wait指定的时间间隔和func函数又未被调用的情况下调用返回值方法，则被调用请求将被丢弃。
     *  options.trailing = true;
     * 注意：当options.trailing = false时，效果与上面的简单实现效果相同
     */
    var context, args, result;
    var timeout = null;
    var previous = 0;
    if (!options) options = {};
    var later = function() {
        previous = options.leading === false ? 0 : new Date().getTime();
        timeout = null;
        result = func.apply(context, args);
        if (!timeout) context = args = null;
    };
    return function() {
        var now = new Date().getTime();
        if (!previous && options.leading === false) previous = now;
        // 计算剩余时间
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        // 当到达wait指定的时间间隔，则调用func函数
        // 精彩之处：按理来说remaining <= 0已经足够证明已经到达wait的时间间隔，但这里还考虑到假如客户端修改了系统时间则马上执行func函数。
        if (remaining <= 0 || remaining > wait) {
            // 由于setTimeout存在最小时间精度问题，因此会存在到达wait的时间间隔，但之前设置的setTimeout操作还没被执行，因此为保险起见，这里先清理setTimeout操作
            if (timeout) {
                clearTimeout(timeout);
                timeout = null;
            }
            previous = now;
            result = func.apply(context, args);
            if (!timeout) context = args = null;
        } else if (!timeout && options.trailing !== false) {
            // options.trailing=true时，延时执行func函数
            timeout = setTimeout(later, remaining);
        }
        return result;
    };
};

export function toTree(list) {
    let map = {};
    list.forEach(function (item) {
        map[item.id] = item;
    });

    let val = [];
    list.forEach(function (item) {
        // 以当前遍历项，的pid,去map对象中找到索引的id
        var parent = map[item.parent];
        // 如果找到索引，那么说明此项不在顶级当中,那么需要把此项添加到，他对应的父级中
        if (parent) {
            (parent.children || (parent.children = [])).push(item);
        } else {
            //如果没有在map中找到对应的索引ID,那么直接把 当前的item添加到 val结果集中，作为顶级
            val.push(item);
        }
    });
    return val
}

export function zip(obj) {
    let zipped = []
    let size = Infinity
    let keys = []
    for (let key in obj) {
        if (obj.hasOwnProperty(key) && Array.isArray(obj[key])) {
            keys.push(key)
            size = Math.min(obj[key].length, size)
        }
    }

    for (let i = 0; i < size; i++) {
        let item = {}
        for (let j = 0; j < keys.length; j++) {
            item[keys[j]] = obj[keys[j]][i]
        }
        zipped.push(item)
    }

    return zipped
}

// 将 {key: value} => [{name: xx, value: xx}]
export function o2l(obj, field = 'name') {
    let l = []
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            l.push({field: key, value: obj[key]})
        }
    }
    return l
}

// 将 [{filed: xx, value: xx}] => {key: value}
export function l2o(list, field = 'name') {
    let obj = {}
    for (let i = 0; i < list.length; i++) {
        obj[list[i][field]] = list[i].value !== null &&
        typeof list[i].value == "object" && list[i].inputType != 'upload' ? list[i].value.value : list[i].value
    }
    return obj
}

export function first(list, key, value) {
    for (let i = 0; i < list.length; i++) {
        if (list[key] === value) {
            return list[i]
        }
    }
    return null
}

// headers => json data
export function toJsonData(headers, data) {
    let newData = []
    data.forEach(item => {
        let json = {}
        headers.forEach((header, index) => {
            json[header] = item[index]
        })
        newData.push(json)
    })

    return newData;
}


function downloadFile(fileName, content) {
    let aLink = document.createElement('a');
    let blob = new Blob([content]);
    let evt = document.createEvent("HTMLEvents");
    evt.initEvent("click", false, false);//initEvent 不加后两个参数在FF下会报错
    aLink.download = fileName;
    aLink.href = URL.createObjectURL(blob);
    aLink.click()
    URL.revokeObjectURL(blob);
}

// export excel
export function tableToExcel(headers, data, wsname, wbname) {
    let uri = 'data:application/vnd.ms-excel;base64,'
        ,
        tmplWorkbookXML = '<?xml version="1.0"?><?mso-application progid="Excel.Sheet"?><Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"'
            + ' xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
            + '<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office"><Author>Axel Richter</Author>'
            + '<Created>{created}</Created></DocumentProperties>'
            + '<Styles>'
            + '<Style ss:ID="Currency"><NumberFormat ss:Format="Currency"></NumberFormat></Style>'
            + '<Style ss:ID="Date"><NumberFormat ss:Format="Medium Date"></NumberFormat></Style>'
            + '</Styles>'
            + '{worksheets}</Workbook>'
        , tmplWorksheetXML = '<Worksheet ss:Name="{nameWS}"><Table>{rows}</Table></Worksheet>'
        , tmplCellXML = '<Cell><Data ss:Type="{nameType}">{data}</Data></Cell>'
        , base64 = function (s) {
            return window.btoa(unescape(encodeURIComponent(s)))
        }
        , format = function (s, c) {
            return s.replace(/{(\w+)}/g, function (m, p) {
                return c[p];
            })
        }


    // get headers
    let rowsXML = "<Row>";
    headers.forEach(item => {
        let cellVal = item.label ? item.label : item.value
        rowsXML += format(tmplCellXML, {
            attributeStyleID: '',
            nameType: 'String',
            data: cellVal,
        });
    })
    rowsXML += '</Row>'
    // get rows
    data.forEach(item => {
        rowsXML += '<Row>'
        for (let i = 0; i < headers.length; i++) {
            let cellVal = item[headers[i].value]
            if (headers[i].type === 'Number' &&  typeof cellVal === 'string') {
                cellVal = cellVal.length ? parseFloat(cellVal.replace(/[^0-9.]/ig, "")) : 0
            }

            rowsXML += format(tmplCellXML, {
                attributeStyleID: '',
                nameType: headers[i].type ? headers[i].type : 'String',
                data: cellVal ? cellVal : '',
                attributeFormula: ''
            });
        }
        rowsXML += '</Row>'
    })
    let ctx = {rows: rowsXML, nameWS: wsname || 'Sheet'};
    let worksheetsXML = format(tmplWorksheetXML, ctx);

    ctx = {created: (new Date()).getTime(), worksheets: worksheetsXML};
    let workbookXML = format(tmplWorkbookXML, ctx);

    downloadFile(wbname + '.xls', workbookXML)

    // let link = document.createElement("A");
    // link.href = uri + base64(workbookXML);
    // link.download = wbname || 'Workbook.xls';
    // link.target = '_blank';
    // document.body.appendChild(link);
    // link.click();
    // document.body.removeChild(link);

    rowsXML = "";
}

export function genUrlParams(obj) {
    let arr = []
    let str = ''
    for (let key in obj) {
        arr.push(`${key}=${obj[key]}`)
    }
    str = arr.join("&")
    return str
}

export function getCookie(name) {
    var arr, reg = new RegExp("(^| )" + name + "=([^;]*)(;|$)");
    if (arr = document.cookie.match(reg))
        return unescape(arr[2]);
    else
        return null;
}

export function getAjaxConf(model, key, value, searchKeys, removeDuplicate) {
    return {
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        },
        delay: 250,
        type: 'POST',
        dataType: 'json',
        xhrFields: {withCredentials: true},
        url: config.serverURI + config.api.model_opt + `${model}/search`,
        data: (params) => {
            let search_keys = {}
            search_keys[`${value}__icontains`] =  params.term
            if (searchKeys) search_keys = Object.assign({}, search_keys, searchKeys)

            let query = {
                search_keys: search_keys,
                page_size: 999,
                order_by: value
            }
            // Query parameters will be ?search=[term]&type=public
            return JSON.stringify(query);
        },
        beforeSend: (xhr) => {
            xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'))
        },
        processResults: (data) => {
            let results = []
            if (removeDuplicate) {
                let tmp = {}
                data.list.forEach( item => {
                    if (!tmp[item[value]]) {
                        tmp[item[value]] = true
                        results.push({
                            id: item[key],
                            text: item[value]
                        })
                    }
                } )
            } else {
                results = data.list.map(item => {
                    return {
                        id: item[key],
                        text: item[value]
                    }
                })
            }
            return {
                results: results
            }

        }
    }
}

export function getCheckListconf() {
    return {
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        },
        delay: 250,
        type: 'POST',
        dataType: 'json',
        xhrFields: {withCredentials: true},
        url: config.serverURI + config.api.model_opt + `CheckList/search`,
        data: (params) => {
            let search_keys = {
                is_template: true
            }
            // search_keys[`item_name__icontains`] =  params.term
            let query = {
                search_keys: search_keys,
                page_size: 9999,
            }
            // Query parameters will be ?search=[term]&type=public
            return JSON.stringify(query);
        },
        beforeSend: (xhr) => {
            xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'))
        },
        processResults: (data) => {
            let results = []
            let list = data.list
            let map = {}
            list.forEach(checklist => {
                checklist.checklist_items.forEach(item => {
                    if (!map[item.item_name]) {
                        results.push({
                            id: item.item_name,
                            text: item.item_name
                        })
                        map[item.item_name] = true
                    }
                })
            })
            map = null
            return {
                results: results
            }
        }
    }
}

export function getBussinessSupportAjaxConf() {
    return {
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        },
        delay: 250,
        type: 'GET',
        dataType: 'json',
        xhrFields: {withCredentials: true},
        url: config.serverURI + config.api.bussiness_support_list,
        data: (params) => {
            let search_keys = {}
            search_keys['bussiness-support'] =  params.term

            let query = {
                search_keys: search_keys,
                page_size: 200,
            }
            // Query parameters will be ?search=[term]&type=public
            return JSON.stringify(query);
        },
        beforeSend: (xhr) => {
            xhr.setRequestHeader('X-CSRFToken', getCookie('csrftoken'))
        },
        processResults: (res) => {
            return {
                results: res.data.map(item => {
                    return {
                        id: item.business_support,
                        text: item.business_support
                    }
                })
            }

        }
    }
}

export function matchAllImgSrc(str) {
    //1，匹配出图片img标签（即匹配出所有图片），过滤其他不需要的字符
    //2.从匹配出来的结果（img标签中）循环匹配出图片地址（即src属性）
    //匹配图片（g表示匹配所有结果i表示区分大小写）
    var imgReg = /<img.*?(?:>|\/>)/gi;
    //匹配src属性
    var srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i;
    var arr = str.match(imgReg);
    var arrSrc = []
    for (var i = 0; i < arr.length; i++) {
        var src = arr[i].match(srcReg);
        //获取图片地址
        if(src[1]){
            arrSrc.push(src[1])
        }
    }
    return arrSrc
}